package net.xiaoboli.mgp;

import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.ConnectionFactory;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.mybatis.generator.internal.JDBCConnectionFactory;
import org.mybatis.generator.internal.ObjectFactory;
import org.mybatis.generator.logging.Log;
import org.mybatis.generator.logging.LogFactory;

import java.sql.*;
import java.time.Instant;
import java.util.Date;
import java.util.List;

/**
 * function import  plugin
 */
public class FunctionPlugin extends PluginAdapter {

    private String[] icons;
    private String c, r, u, d, f;
    private String functionPid;
    private String functionTable;
    private String contextPath;
    private String viewPath;
    private Log log;

    @Override
    public boolean validate(List<String> list) {
        functionTable = properties.getProperty("functionTable");
        contextPath = properties.getProperty("contextPath", "/");
        viewPath = properties.getProperty("viewPath", "/");

        functionPid = properties.getProperty("functionPid", "-");
        if (StringUtils.isEmpty(functionPid)) {
            functionPid = "-";
        }

        if (functionTable == null || functionTable.trim().length() == 0)
            functionTable = "sys_func";

        if (contextPath.trim().length() == 0)
            contextPath = "/";

        if (!contextPath.endsWith("/"))
            contextPath = contextPath + "/";

        if (!contextPath.startsWith("/"))
            contextPath = "/" + contextPath;


        if (viewPath.trim().length() == 0)
            viewPath = "/";

        if (!viewPath.endsWith("/"))
            viewPath = viewPath + "/";

        if (!viewPath.startsWith("/"))
            viewPath = "/" + viewPath;


        c = properties.getProperty("C");
        r = properties.getProperty("R");
        u = properties.getProperty("U");
        d = properties.getProperty("D");
        f = properties.getProperty("F");

        if (StringUtils.isEmpty(c)) c = "Add %s";
        if (StringUtils.isEmpty(r)) r = "View %s";
        if (StringUtils.isEmpty(u)) u = "%s Update";
        if (StringUtils.isEmpty(d)) d = "Delete %s";
        if (StringUtils.isEmpty(f)) f = "%s";


        String icons = properties.getProperty("icons", "el-icon-orange,el-icon-circle-plus,el-icon-edit,el-icon-remove,el-icon-view");
        if (icons.equals("")) {
            this.icons = new String[]{"", "", "", "", ""};
        }
        this.icons = icons.split(",");
        if (this.icons.length != 5) {
            list.add("icons must exactly five elements");
            log.error("icons must exactly five elements");
            return false;
        }

        return true;
    }


    @SneakyThrows
    @Override
    public void initialized(IntrospectedTable introspectedTable) {
        this.log = LogFactory.getLog(this.getClass());

        String noFunction = introspectedTable.getTableConfigurationProperty("function");
        if ("no".equals(noFunction)) {
            log.warn(introspectedTable.getFullyQualifiedTableNameAtRuntime() + " function skip create because function configured to no");
            return;
        }

        try {
            this.addFunction(introspectedTable);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    private Connection getConnection() throws SQLException {
        Object connectionFactory;
        JDBCConnectionConfiguration jdbcConnectionConfiguration = context.getJdbcConnectionConfiguration();
        if (jdbcConnectionConfiguration != null) {
            connectionFactory = new JDBCConnectionFactory(jdbcConnectionConfiguration);
        } else {
            connectionFactory = ObjectFactory.createConnectionFactory(context);
        }
        return ((ConnectionFactory) connectionFactory).getConnection();
    }

    private int queryLastOrderNumber(String pid) throws SQLException {
        int lastOrderNum = 0;

        try (Connection connection = this.getConnection()) {
            String sql = "";
            PreparedStatement preparedStatement;
            //从主路径判断是否已被添加过
            sql = "SELECT max(order_num) FROM " + functionTable + " WHERE pid='" + pid + "'";
            preparedStatement = connection.prepareStatement(sql);
            try (ResultSet rs = preparedStatement.executeQuery()) {
                if (rs.next()) {
                    lastOrderNum = rs.getInt(1);
                }
            }
        }

        return lastOrderNum;
    }

    private void addFunction(IntrospectedTable introspectedTable) throws SQLException {
        Date now = new Date();
        Instant d2020 = Instant.parse("2021-01-01T00:00:00.00Z");
        try (Connection connection = this.getConnection()) {

            String recordType = introspectedTable.getBaseRecordType();
            String modelName = recordType.substring(recordType.lastIndexOf(".") + 1);
            String remarks = introspectedTable.getRemarks();

            if (StringUtils.isEmpty(remarks)) {
                remarks = modelName;
            }

            String n = modelName;
            String p = PluginUtil.modelToPath(introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime());
            String ni = PluginUtil.modelToName(introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime());
            String[] permissions = new String[]{n + ".Read", n + ".Create", n + ".Update", n + ".Delete", n + ".Read"};
            String[] functions = new String[]{p + "/list", p + "/add", p + "/edit", p + "/del", p + "/info"};
            String[] views = new String[]{p + "/list", p + "/add", p + "/edit", p + "/del", p + "/info"};
            String[] ids = new String[]{ni + ".list", ni + ".add", ni + ".edit", ni + ".del", ni + ".info"};
            String[] names = new String[]{String.format(f, remarks), String.format(c, remarks), String.format(u, remarks)
                    , String.format(d, remarks), String.format(r, remarks)};

            //icons = "el-icon-orange,el-icon-circle-plus,el-icon-edit,el-icon-remove,el-icon-view,el-icon-list";

            //增加前缀 / 及配置的 context_path
            for (int i = 0; i < functions.length; i++) {
                functions[i] = contextPath + functions[i];
                views[i] = viewPath + views[i];
            }

            String sql = "";
            PreparedStatement preparedStatement;

//            CREATE TABLE sys_func (
//                    id		 					int			 	auto_increment		COMMENT '主键'
//                    ,pid						int			 	DEFAULT NULL 		COMMENT '父级id'
//                    ,name 						varchar(255) 	DEFAULT NULL 		COMMENT '功能名称'
//                    ,order_num 					int			 	DEFAULT 0 			COMMENT '排序序号'
//                    ,fun_method					varchar(50) 	DEFAULT NULL 		COMMENT '请求方式:GET/POST等'
//                    ,fun_path 					varchar(255) 	DEFAULT NULL 		COMMENT '功能地址'
//                    ,fun_type					int			 	DEFAULT 0			COMMENT '0:菜单,1:功能'
//                    ,icon 						varchar(50)  	DEFAULT NULL 		COMMENT '菜单图标'
//                    ,no_visible					int  		 	DEFAULT 0	 		COMMENT '可见性(0:正常, 1:不显示)'
//                    ,is_disabled				int  		 	DEFAULT 0	 		COMMENT '是否禁用(0:正常, 1:禁用)'
//                    ,permission_id				varchar(50)	 	DEFAULT NULL		COMMENT '权限标识'
//                    ,create_time 				datetime(3)	 	default null		COMMENT '创建时间'
//                    ,update_time 				datetime(3)  	default null		COMMENT '更新时间'
//                    ,remark						varchar(250) 	DEFAULT NULL		COMMENT '备注'
//                    ,PRIMARY KEY (id)
//) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='功能表';

            //从主路径判断是否已被添加过
            sql = "SELECT id FROM " + functionTable + " WHERE fun_path=?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, functions[0]);
            ResultSet rs = preparedStatement.executeQuery();
            if (rs.next()) {
                //已被添加过，跳过
                //System.out.println("Function " + functions[0] + " have created, skip table "+ introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime() +" func generate");
                System.out.println("Add function " + functions[0] + " ignore because have created");
                return;
            }

            System.out.println("Add function " + p);

//            //删除旧
//            sql = "DELETE FROM " + functionTable + " WHERE fun_path=?";
//            for (String function : functions) {
//                preparedStatement = connection.prepareStatement(sql);
//                preparedStatement.setString(1, function);
//                preparedStatement.execute();
//            }

            //添加新
            sql = "";
            sql += "INSERT INTO " + functionTable + " ";
            sql += "(pid,name,order_num,fun_path,fun_type,permission_id,create_time,update_time,fun_view,icon,id)";
            sql += "VALUES";
            sql += "(?,  ?   ,?         ,?       ,?      ,?             ,?          ,? ,?,?, ?)";

            //
            Integer funType;
            String id, name, funPath, funView, permissionId, icon, pid = functionPid;
            int orderNum = this.queryLastOrderNumber(functionPid);

            //添加, 索引 0 为该栏目菜单
            for (int i = 0; i < permissions.length; i++) {
                id = ids[i];
                name = names[i];
                orderNum++;
                funPath = functions[i];
                funView = views[i];
                funType = i == 0 ? 0 : 1;
                permissionId = permissions[i];
                icon = this.icons[i];

                this.addFunction(connection, sql, id, pid, name, orderNum, funPath, funView, funType, permissionId, icon);
                if (i == 0) {
                    //第一个为菜单，将ID设置为其它项的父级
                    orderNum = 0;
                    pid = id;
                }
            }
        }

    }

    private void addFunction(Connection connection, String sql, String id, String pid, String name, int orderNum, String funPath, String funView, Integer funType, String permissionId, String icon) throws SQLException {
        Date now = new Date();

        PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        preparedStatement.setString(1, pid);
        preparedStatement.setString(2, name);
        preparedStatement.setInt(3, orderNum);
        preparedStatement.setString(4, funPath);
        preparedStatement.setInt(5, funType);
        preparedStatement.setString(6, permissionId);
        preparedStatement.setTimestamp(7, new Timestamp(now.getTime()));
        preparedStatement.setTimestamp(8, new Timestamp(now.getTime()));
        preparedStatement.setString(9, funView);
        preparedStatement.setString(10, icon);
        preparedStatement.setString(11, id);
        preparedStatement.execute();

        ResultSet generatedKeys = preparedStatement.getGeneratedKeys();
        generatedKeys.next();
//        Integer id = generatedKeys.getInt(1);

        System.out.println(String.format("Add function %s, %s", funPath, name));

    }

}
